﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Reflection;
using popLib.CustomeControl;
using System.Data.Objects;

namespace popLib.ModelSystem
{
    public partial class MainFormModel : Form
    {
        public static MainFormModel _Instance;
        public static MainFormModel Instance { 
            get 
            {
                if (_Instance == null) _Instance = new MainFormModel();
                return _Instance;
            }

            set 
            {
                _Instance = value;
            }
        }
        
        public Icon AppIcon 
        {
            get { return this.Icon; }
            set { this.Icon = value; }
        }

        public Icon AppIconSmall { get; set; }

        public UserAccount CurrentUser { get; set; }
        public string AppTitle { get { return this.Text; } set { this.Text = value; } }

        private DateTime _WorkDate;
        public DateTime WorkDate { get { return _WorkDate; } set { _WorkDate = value; UpdateInterface(); } }
        public bool AllowChangeWorkDate { get; set; }

        public FormWindowState ChildWindowState { get; set; }

        private FormLanguage _Language;
        public FormLanguage Language {
            get { return _Language; }
            set {
                _Language = value;
                switch (_Language)
                {
                    case FormLanguage.English:
                        CustomLanguageSet = new LanguageSet().English();
                        break;
                    case FormLanguage.Vietnamese:
                        CustomLanguageSet = new LanguageSet().Vietnamese();
                        break;
                    case FormLanguage.Custom:
                        if (_CustomLanguageSet == null)
                            CustomLanguageSet = new LanguageSet().English();
                        else
                            CustomLanguageSet = _CustomLanguageSet;
                        break;                    
                }
            }
        }
        
        private LanguageSet _CustomLanguageSet;
        public LanguageSet  CustomLanguageSet {
            get { return _CustomLanguageSet; }
            set
            {
                _CustomLanguageSet = value;
                UpdateInterface();
            }
        }
                        
        public delegate List<MenuInfoItem> MenuListFunctionDelegate(UserAccount account);
        public MenuListFunctionDelegate MenuListFunction { get; set; }

        public delegate ReturnSet LoginFunctionDelegate(string username, string password);
        public LoginFunctionDelegate LoginFunction { get; set; }

        public delegate ReturnSet ChangePasswordDelegate(string username, string oldpassword, string newpassword);
        public ChangePasswordDelegate ChangePasswordFunction { get; set; }

        public delegate DateTime GetServerDateTimeDelegate();
        public GetServerDateTimeDelegate GetServerDateTimeFunction { get; set; }

        public delegate Type GetTypeDelegate(string typename);
        public GetTypeDelegate GetTypeFunction { get; set; }

        public delegate ObjectContext GetDBObjectContextDelegate();
        public GetDBObjectContextDelegate GetDBObjectContextFunction { get; set; }

        public int ItemPerPage { get; set; }
        public List<string> StatusBarItems { get; set; }


        //danh sach user la admin, duoc quyen xem chuc nang quan ly form, role
        public List<UserAccount> AdminUsers { get; set; }

        public MainFormModel(Icon appIcon, string appTitle, FormLanguage language, MenuListFunctionDelegate menuListFunction, LoginFunctionDelegate loginFunction, ChangePasswordDelegate changePasswordFunction, GetServerDateTimeDelegate getServerDateTimeFunction, GetTypeDelegate getTypeFunction, GetDBObjectContextDelegate objectContextFunc)
        {
            InitializeComponent();

            InitForm(appIcon, appTitle, language, menuListFunction, loginFunction, changePasswordFunction, getServerDateTimeFunction, getTypeFunction, objectContextFunc);
        }

        public MainFormModel()
        {
            InitializeComponent();
        }

        public void InitForm(Icon appIcon, string appTitle, FormLanguage language, MenuListFunctionDelegate menuListFunction, LoginFunctionDelegate loginFunction, ChangePasswordDelegate changePasswordFunction, GetServerDateTimeDelegate getServerDateTimeFunction, GetTypeDelegate getTypeFunction, GetDBObjectContextDelegate objectContextFunc)
        {
            if (appIcon != null) AppIcon = appIcon;
            if (appTitle.isValid()) AppTitle = appTitle;
            Language = language;
            MenuListFunction = menuListFunction;
            LoginFunction = loginFunction;
            ChangePasswordFunction = changePasswordFunction;
            GetServerDateTimeFunction = getServerDateTimeFunction;
            GetTypeFunction = getTypeFunction;
            GetDBObjectContextFunction = objectContextFunc;
            
        }


        public void UpdateInterface()
        {
            tsmi_system.Text = _CustomLanguageSet.System;
            tsmi_window.Text = _CustomLanguageSet.Windows;
            tsmis_changePassword.Text = _CustomLanguageSet.ChangePassword;
            tsmis_formMgr.Text = _CustomLanguageSet.RoleManagement;

                        
            if(CurrentUser != null)
                lbl_acc.Text = string.Format("{0}: {1} ({2})", _CustomLanguageSet.User, CurrentUser.Fullname, CurrentUser.Username);

            lbl_acc.Text += string.Format("{0}{1}: {2}", lbl_acc.Text.isValid() ? " | " : "", _CustomLanguageSet.Workdate, WorkDate.ToString(_CustomLanguageSet.WorkdateFormat)  );

            if (StatusBarItems == null) StatusBarItems = new List<string>();
            foreach (var item in StatusBarItems)
            {
                lbl_acc.Text += string.Format("{0}{1}", lbl_acc.Text.isValid() ? " | " : "", item);
            }
            
            tsmis_logout.Text = _CustomLanguageSet.Logout;
        }
        
        public void UpdateUserEnvironment()
        {
            //update langua bar
            Language = Language; 

            //update lai phan quyen cho admin            
            tsmis_formMgr.Visible = false;
            if (AdminUsers != null)
            {
                foreach (var item in AdminUsers)
                {
                    if (CurrentUser.Username == item.Username || (CurrentUser.ID == item.ID && CurrentUser.ID > 0))
                        tsmis_formMgr.Visible = true;
                }
            }


            //rebuild menu
            BuildMenuFromDB();

            //updateInterace
            UpdateInterface();
        }

        private static TimeSpan ShiftTime;
        public static DateTime GetServerDateTime()
        {
            if (ShiftTime.Ticks == 0)
            {
                ShiftTime = MainFormModel.Instance.GetServerDateTimeFunction().Subtract(DateTime.Now);
            }

            return DateTime.Now.Add(ShiftTime);
        }
        
        private void BuildMenuFromDB()
        {
            //remove all menu from mainmenu
            for (int i = MainMenu.Items.Count - 1; i > 0; i--)
            {
                ToolStripMenuItem item = (ToolStripMenuItem)MainMenu.Items[i];
                if (item.Tag != null)
                {
                    item.DropDownItems.Clear();
                    foreach (ToolStripMenuItem subitem in item.DropDownItems)
                    {
                        subitem.Dispose();
                    }
                    MainMenu.Items.Remove(item);
                    item.Dispose();
                }
            }

            int menuIndex = 1;
            bool isFirstItem = false;
            if (MenuListFunction == null)
            {
                FormLib.alert("MenuListFunction is required in order to build form menu.");
                return;
            }

            //lay danh sach menulist cho
            var menuListFull = MenuListFunction(CurrentUser);

            var menuListLevel1 = menuListFull.Where(x => x.ParentMenu_ID == null || x.ParentMenu_ID == 0).ToList();
            foreach (var item in menuListLevel1)
            {
                var rootMenuItem = new ToolStripMenuItem(item.TenMenu);
                rootMenuItem.Tag = 1;
                MainMenu.Items.Insert(menuIndex++, rootMenuItem);

                isFirstItem = true;
                var menuListLevel2 = menuListFull.Where(x => x.ParentMenu_ID == item.Menu_ID).ToList();
                foreach (var item1 in menuListLevel2)
                {
                    var subMenuItem = new ToolStripMenuItem(item1.TenMenu);

                    if (!isFirstItem && item1.TopSeparator != null && (bool)item1.TopSeparator == true)
                    {
                        var separator = new ToolStripSeparator();
                        rootMenuItem.DropDownItems.Add(separator);
                    }
                    

                    rootMenuItem.DropDownItems.Add(subMenuItem);

                    var menuListLevel3 = menuListFull.Where(x => x.ParentMenu_ID == item1.Menu_ID).ToList();
                    if (menuListLevel3.Count > 0)
                    {
                        isFirstItem = true;
                        foreach (var item2 in menuListLevel3)
                        {
                            var secondSubMenuItem = new ToolStripMenuItem(item2.TenMenu);

                            if (!isFirstItem && item2.TopSeparator != null && (bool)item2.TopSeparator == true)
                            {
                                var separator = new ToolStripSeparator();
                                subMenuItem.DropDownItems.Add(separator);
                            }

                            subMenuItem.DropDownItems.Add(secondSubMenuItem);
                            secondSubMenuItem.Tag = item2;
                            secondSubMenuItem.Click += oneone_Click;

                            isFirstItem = false;
                        }
                    }
                    else
                    {
                        subMenuItem.Tag = item1;
                        subMenuItem.Click += oneone_Click;
                    }

                    isFirstItem = false;
                }
            }
        }

        private void oneone_Click(object sender, EventArgs e)
        {

            MenuInfoItem menu = (MenuInfoItem)((ToolStripMenuItem)sender).Tag;

            //Type type = Type.GetType(menu.PathForm);
            Type type = GetTypeFunction(menu.PathForm);

            if (ShowExistedWindow(type).Success)
                return;

            Form form = (Form)Activator.CreateInstance(type, new object[] { new FormAction(menu) });

            if(AppIconSmall != null)
                form.Icon = AppIconSmall;
            else
                form.Icon = AppIcon;
            
            form.MdiParent = this;

            if (ChildWindowState == null) ChildWindowState = FormWindowState.Normal;
            form.WindowState = ChildWindowState;

            form.Show();
        }

        public ReturnSet ShowExistedWindow(Type type)
        {
            foreach (var child in MdiChildren)
            {
                if (child.GetType().Equals(type))
                {
                    child.BringToFront();

                    if (child.WindowState == FormWindowState.Minimized)
                    {
                        child.WindowState = FormWindowState.Normal;
                    }
                    return new ReturnSet(true, child);
                }
            }
            return new ReturnSet(false);
        }

        public void AddMDIChild(Form form)
        {
            form.MdiParent = this;
            form.Show();
        }


        private void tsmis_changePassword_Click(object sender, EventArgs e)
        {
            new UpdatePassword().ShowDialog();
        }

        private void tsmis_formMgr_Click(object sender, EventArgs e)
        {
            if (ShowExistedWindow(typeof(FormManagement)).Success)
                return;

            FormManagement form = new FormManagement();

            form.MdiParent = this;
            form.Show();
        }

        private void tsmis_logout_Click(object sender, EventArgs e)
        {
            if (!CloseChildForms())
                return;

            this.Hide();

            Login form = new Login();
            form.ShowDialog();

            if (form.DialogResult == System.Windows.Forms.DialogResult.OK)
            {
                UpdateUserEnvironment();
                this.Show();
            }
            else
            {
                this.Close();
            }
        }

        private bool CloseChildForms()
        {
            if (MdiChildren.Length > 0)
            {
                FormLib.alert(CustomLanguageSet.ForceCloseFormMessage, CustomLanguageSet.MessageBoxTitle);
                return false;
            }
            return true;
        }
    }

    public class UserAccount
    {
        public string Username { get; set; }
        public string Fullname { get; set; }        
        public int ID { get; set; }
        public Hashtable AccountData { get; set; }
    }

    public class LanguageSet
    {
        public string System {get; set; }
        public string ChangePassword { get; set; }
        public string RoleManagement { get; set; }
        public string Logout { get; set; }
        public string Windows { get; set; }
        public string User { get; set; }
        public string ForceCloseFormMessage { get; set; }
        public string MessageBoxTitle { get; set; }
        public string InputFieldTitle { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
        public string RememberPassword { get; set; }
        public string Cancel { get; set; }
        public string Workdate { get; set; }
        public string WorkdateFormat { get; set; }

        public string DB_RecordOutOfDate { get; set; }
        public string DB_AddExistedRecord { get; set; }
        public string DB_RecordNotExisted { get; set; }
        public string DB_UnknownError { get; set; }
        public string DB_AccountIsNotExisted { get; set; }
        public string DB_PasswordIsNotCorrect { get; set; }
        public string DB_AccountIsLocked { get; set; }
        public string DB_DataLengthTruncated { get; set; }

        public string FRM_UpdateSuccess { get; set; }
        public string FRM_UpdateFail { get; set; }
        public string FRM_AddSuccessConfirm { get; set; }
        public string FRM_AddFail { get; set; }
        public string FRM_DisposeSuccess { get; set; }
        public string FRM_DisposeFail { get; set; }
        public string FRM_ConfirmDispose { get; set; }
        public string FRM_ConfirmCancel { get; set; }
        public string FRM_ConfirmAccept { get; set; }
        public string FRM_CloseFormNotReady { get; set; }
        public string FRM_RecordNotFound { get; set; }
        public string FRM_ReportNotFound { get; set; }
        public string FRM_LoginFail { get; set; }
        public string FRM_NotAllơwDisposeRelateReportData { get; set; }
        public string FRM_ConfirmDisposeNoReason { get; set; }
        public string FRM_ConfirmRequireInput { get; set; }

        public LanguageSet()
        {               
        }

        public LanguageSet English()
        {
            System = "System";
            ChangePassword = "Change Password";
            RoleManagement = "Account & Role Management";
            Logout = "Logout";
            Windows = "Windows";
            User = "User";
            ForceCloseFormMessage = "Please close all running forms in order to logout";
            MessageBoxTitle = "Message";
            InputFieldTitle = "Content";
            Username = "Username";
            Password = "Password";
            RememberPassword = "Remember login information";
            Cancel = "Cancel";
            Workdate = "Working date";
            WorkdateFormat = "yyyy-MM-dd";

            DB_RecordOutOfDate = "Data record {0} was modified by others.";
            DB_AddExistedRecord = "Data record {0} is already existed.";
            DB_RecordNotExisted = "Cannot find data record {0}.";
            DB_UnknownError = "Unknown error, cannot update data record {0}.";
            DB_AccountIsNotExisted = "This account {0} is not found in system.";
            DB_PasswordIsNotCorrect = "Password is not correct.";
            DB_AccountIsLocked = "This account {0} is locked by admin.";
            DB_DataLengthTruncated = "Data's length exceeds limit";

            FRM_UpdateSuccess = "{0} is updated sucessfully";
            FRM_UpdateFail = "Fail to update {0}.\r\nplease try again later.";
            FRM_AddSuccessConfirm = "{0} is added sucessfully. Do you want to add more {0}?";
            FRM_AddFail = "Fail to add {0}.";
            FRM_DisposeSuccess = "{0} is diposed sucessfully.";
            FRM_DisposeFail = "Fail to dispose {0}.\r\nPlease try again later.";
            FRM_ConfirmDispose = "Are you sure you want to dispose this {0}?";
            FRM_ConfirmCancel = "Are you sure you want to cancel?\r\nAll changes will not be saved.";
            FRM_ConfirmAccept = "Are you sure you want to confirm for {0}?";
            FRM_CloseFormNotReady = "Please save or cancel before close form.";
            FRM_RecordNotFound = "Cannot find {0}.";
            FRM_ReportNotFound = "Cannot find report file {0}.";
            FRM_LoginFail = "Cannot login.";
            FRM_NotAllơwDisposeRelateReportData = "Diposing this record is not allowed because report data is locked.";
            FRM_ConfirmDisposeNoReason = "Are you sure you want to dispose this {0}?";
            FRM_ConfirmRequireInput = "Please enter all require information of {0}";
            return this;
        }

        public LanguageSet Vietnamese()
        {
            System = "Hệ thống";
            ChangePassword = "Thay đổi mật khẩu";
            Logout = "Đăng xuất";
            RoleManagement = "Quản lý phân quyền";
            User = "Người dùng";
            Windows = "Cửa sổ";
            ForceCloseFormMessage = "Xin vui lòng đóng tất cả các cửa sổ trước khi đăng xuất";
            MessageBoxTitle = "Thông báo";
            InputFieldTitle = "Nội dung";
            Cancel = "Thoát";
            Password = "Mật khẩu";
            RememberPassword = "Ghi nhớ thông tin đăng nhập";
            Username = "Tên đăng nhập";
            Workdate = "Ngày làm việc";
            WorkdateFormat = "dd/MM/yyyy";

            DB_RecordOutOfDate = "Chứng từ/bản ghi {0} này đã bị chỉnh sửa bởi người khác";
            DB_AddExistedRecord = "Chứng từ/bản ghi {0} này đã tồn tại";
            DB_RecordNotExisted = "Không tìm thấy chứng từ/bản ghi {0} này";
            DB_UnknownError = "Không thể cập nhật chứng từ/bản ghi {0} này";
            DB_AccountIsNotExisted = "Tài khoản {0} này không tồn tại trong hệ thống";
            DB_PasswordIsNotCorrect = "Mật khẩu không chính xác";
            DB_AccountIsLocked = "Tài khoản {0} này đã bị khóa; xin vui lòng liên hệ quản trị mạng";
            DB_DataLengthTruncated = "Dữ liệu nhập vào dài hơn độ dài cho phép";

            FRM_UpdateSuccess = "Cập nhật {0} thành công";
            FRM_UpdateFail = "Không thể cập nhật {0} này đuợc.\r\nXin vui lòng thử lại lần sau.";
            FRM_AddSuccessConfirm = "Thêm mới {0} thành công\r\nBạn có muốn thêm mới {0} nữa không?";
            FRM_AddFail = "Thêm mới {0} không thành công";
            FRM_DisposeSuccess = "Hủy chứng từ {0} thành công";
            FRM_DisposeFail = "Hủy chứng từ {0} không thành công.\r\nXin vui lòng thử lại lần sau.";
            FRM_ConfirmDispose = "Bạn có chắc là bạn muốn hủy chứng từ {0} này không?";
            FRM_ConfirmCancel = "Bạn có chắc là bạn muốn hủy thao tác không?\r\nMọi thay đổi của bạn sẽ không được lưu lại.";
            FRM_ConfirmAccept = "Bạn có chắc là bạn muốn xác nhận cho {0} này không?";
            FRM_CloseFormNotReady = "Bạn phải lưu lại hoặc hủy thao tác trước khi đóng cửa sổ này";
            FRM_RecordNotFound = "Không tìm thấy {0}";
            FRM_ReportNotFound = "Không tìm thấy tập tin báo cáo mẫu [{0}]";
            FRM_LoginFail = "Đăng nhập không thành công";
            FRM_NotAllơwDisposeRelateReportData = "Bạn không thể hủy chứng từ này được do dữ liệu báo cáo đã bị khóa";
            FRM_ConfirmDisposeNoReason = "Bạn có chắc là bạn muốn hủy chứng từ {0} này không?";
            FRM_ConfirmRequireInput = "Xin vui lòng nhập thêm thông tin bổ sung {0}";

            return this;
        }
    }

    public class MenuInfoItem
    {

        public MenuInfoItem(object obj2Parser)
        {
            PropertyInfo[] properties = this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
            PropertyInfo[] properties2 = obj2Parser.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);

            foreach (PropertyInfo property in properties)
            {
                var rs = properties2.Where(x => x.Name == property.Name);
                if (rs.Count() == 0) continue;
                property.SetValue(this, rs.First().GetValue(obj2Parser, null), null);
            }
        }

        public MenuInfoItem() { }

        public int Menu_ID { get; set; }
        public bool AddRecord { get; set; }
        public bool ConfirmRecord { get; set; }
        public bool ConfirmRecordOwner { get; set; }
        public bool DisposeRecord { get; set; }
        public bool DisposeRecordOwner { get; set; }
        public bool EditRecord { get; set; }
        public bool EditRecordOwner { get; set; }
        public string ExtraParam { get; set; }
        public int Form_ID { get; set; }
        public bool FullPermission { get; set; }
        public int MenuIndex { get; set; }
        public int Module_ID { get; set; }
        public int ParentMenu_ID { get; set; }
        public string PathForm { get; set; }
        public bool PrintRecord { get; set; }
        public bool PrintRecordOwner { get; set; }
        public bool SuDung { get; set; }
        public string TaiKhoan { get; set; }
        public string TenForm { get; set; }
        public string TenMenu { get; set; }
        public bool TopSeparator { get; set; }
        public bool ViewRecord { get; set; }
        public bool ViewRecordOwner { get; set; }
    }
}
